﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Mail;
using System.Threading;
using MassMailing.WPF.Content;
using MassMailing.WPF.Settings;

namespace MassMailing.WPF.Commands
{
    /// <summary>
    /// A command that performs the mass mailing.
    /// </summary>
    public class MassMailingCommand : BaseCommand
    {
        #region Fields

        public event AsyncCompletedEventHandler MessageSent;
        public event SendCompletedEventHandler SendCompleted;

        private SMTPSetting _smtpSetting;
        private IEnumerable<Recipient> _recipients;
        private MassMailingMessage _message;
        private List<SendMailCommand> _sendMailCommands;

        #endregion

        #region Constructor
        
        /// <summary>
        /// Default Constructor for the Mass Mailing Command.
        /// </summary>
        /// <param name="smtpSetting">The smtp settings for the mass mailing.</param>
        /// <param name="recipients">The recipients for the mass mailing.</param>
        /// <param name="message">The message to send to the recipients.</param>
        public MassMailingCommand(SMTPSetting smtpSetting, IEnumerable<Recipient> recipients, MassMailingMessage message)
        {
            _smtpSetting = smtpSetting;
            _recipients = recipients;
            _message = message;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// The event handler for the message sent event on the send mail command.
        /// </summary>
        private void SendMail_MessageSent(object sender, AsyncCompletedEventArgs e)
        {
            RaiseMessageSent(sender, e);
        }

        /// <summary>
        /// The event handler for the send completed event on the send mail command.
        /// </summary>
        private void SendMail_SendCompleted(object sender, AsyncCompletedEventArgs e)
        {
            RaiseSendCompleted(sender, e);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The method that performs the Mass Mailing Command.
        /// </summary>
        protected override void PerformCommand()
        {
            _sendMailCommands = new List<SendMailCommand>();

            foreach (Recipient recipient in _recipients)
            {
                SendMailCommand sendMail = new SendMailCommand(_smtpSetting, recipient, _message);
                sendMail.MessageSent += new AsyncCompletedEventHandler(SendMail_MessageSent);
                sendMail.SendCompleted += new SendCompletedEventHandler(SendMail_SendCompleted);
                _sendMailCommands.Add(sendMail);

                if (_smtpSetting.BurstSize.HasValue && _sendMailCommands.Count == _smtpSetting.BurstSize.Value)
                {
                    ExecuteCommandsAndWait(_sendMailCommands);
                    if (_smtpSetting.BurstDelay.HasValue && _smtpSetting.BurstSize.Value > 0)
                        Thread.Sleep(_smtpSetting.BurstDelay.Value * 1000);
                    _sendMailCommands = new List<SendMailCommand>();
                }
            }

            if (_sendMailCommands.Any())
            {
                ExecuteCommandsAndWait(_sendMailCommands);
            }
        }

        /// <summary>
        /// Raises the message sent event.
        /// </summary>
        /// <param name="sender">The sender that created the event.</param>
        /// <param name="e">The event args that are associated with this event.</param>
        private void RaiseMessageSent(object sender, AsyncCompletedEventArgs e)
        {
            if (MessageSent != null)
            {
                MessageSent(sender, e);
            }
        }

        /// <summary>
        /// Raises the send completed event.
        /// </summary>
        /// <param name="sender">The sender that created the event.</param>
        /// <param name="e">The event args that are associated with this event.</param>
        private void RaiseSendCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (SendCompleted != null)
            {
                SendCompleted(sender, e);
            }
        }

        #endregion
    }
}
